home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / mail / ymail.pyo (.txt) < prev   
Python Compiled Bytecode  |  2008-10-13  |  18KB  |  579 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. import traceback
  6. import cookielib
  7. import urllib2
  8. from threading import Lock
  9. from datetime import datetime
  10. from urlparse import urlparse
  11. from urllib import quote
  12. from logging import getLogger
  13. from mail import Email, MailException
  14. from util import UrlQuery, WebFormData, get_func_name, GetDefaultHandlers, threaded
  15. from common.emailaccount import EmailAccount
  16. log = getLogger('YahooMail')
  17.  
  18. class YahooMailException(MailException):
  19.     pass
  20.  
  21.  
  22. class YahooMailAuthException(YahooMailException):
  23.     pass
  24.  
  25.  
  26. class YahooMailBadDataException(YahooMailException):
  27.     pass
  28.  
  29.  
  30. class YahooMailNoAccountException(YahooMailBadDataException):
  31.     pass
  32.  
  33. SessionIdReissue = 'Client.ClientRedirect.SessionIdReissue'
  34. ExpiredCredentials = 'Client.ExpiredCredentials'
  35. backup_server = 'us.mg1.mail.yahoo.com'
  36.  
  37. def ymail_action(func):
  38.     
  39.     def ymail_action_wrapper(self, *a, **k):
  40.         if self._current_action is None:
  41.             self._current_action = func.func_name
  42.         
  43.         
  44.         try:
  45.             return func(self, *a, **k)
  46.         except YahooMailAuthException:
  47.             e = None
  48.             self.bad_pw()
  49.         except YahooMailNoAccountException:
  50.             e = None
  51.             self.no_mailbox()
  52.         except Exception:
  53.             e = None
  54.             traceback.print_exc()
  55.         finally:
  56.             self._current_action = None
  57.  
  58.  
  59.     return threaded(ymail_action_wrapper)
  60.  
  61.  
  62. class YahooMail(EmailAccount):
  63.     protocol = 'ymail'
  64.     default_domain = 'yahoo.com'
  65.     
  66.     def __init__(self, *args, **kwargs):
  67.         EmailAccount.__init__(self, *args, **kwargs)
  68.         self.init_jar()
  69.         self.update_lock = Lock()
  70.         self.updated_emails = None
  71.         self.updated_count = None
  72.         self.isBeta = True
  73.         self._current_action = None
  74.  
  75.     
  76.     def timestamp_is_time(self, tstamp):
  77.         return False
  78.  
  79.     
  80.     def get_email_address(self):
  81.         val = getattr(self, '_default_send_address', None)
  82.         if not val:
  83.             pass
  84.         return EmailAccount.get_email_address(self)
  85.  
  86.     
  87.     def init_jar(self):
  88.         
  89.         try:
  90.             del self.u
  91.         except AttributeError:
  92.             pass
  93.  
  94.         
  95.         try:
  96.             del self._json_endpoint
  97.         except AttributeError:
  98.             pass
  99.  
  100.         self.jar = cookielib.CookieJar()
  101.         self.http_opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.jar), *GetDefaultHandlers())
  102.         self.http_opener.addheaders = [
  103.             ('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3')]
  104.  
  105.     
  106.     def get_json_endpoint(self):
  107.         
  108.         try:
  109.             return self._json_endpoint
  110.         except AttributeError:
  111.             self._json_endpoint = UrlQuery('http://' + self.hostname + '/ws/mail/v1.1/jsonrpc', appid = 'YahooMailRC')
  112.             return self._json_endpoint
  113.  
  114.  
  115.     
  116.     def set_json_endpoint(self, val):
  117.         self._json_endpoint = val
  118.  
  119.     json_endpoint = property(get_json_endpoint, set_json_endpoint)
  120.     
  121.     def _reset_state(self):
  122.         self.init_jar()
  123.         
  124.         try:
  125.             del self.u
  126.         except AttributeError:
  127.             pass
  128.  
  129.         
  130.         try:
  131.             del self._json_endpoint
  132.         except AttributeError:
  133.             pass
  134.  
  135.  
  136.     
  137.     def update(self):
  138.         log.error('ymail.update called from %s', get_func_name(2))
  139.         if self.offline_reason == self.Reasons.BAD_PASSWORD and hasattr(self, 'u'):
  140.             self.init_jar()
  141.         
  142.         EmailAccount.update(self)
  143.         self.real_update(success = self.finish_update, error = self.warning)
  144.  
  145.     
  146.     def warning(self, e = None):
  147.         log.warning('yahoo blew up: %s', e)
  148.         log.error('ymail.warning called from %s', get_func_name(2))
  149.         if isinstance(e, YahooMailAuthException):
  150.             self.bad_pw()
  151.         else:
  152.             self.on_error(self._current_action)
  153.         return True
  154.  
  155.     
  156.     def bad_pw(self):
  157.         self.init_jar()
  158.         EmailAccount.bad_pw(self)
  159.  
  160.     
  161.     def finish_update(self, update):
  162.         if self.state == self.Statuses.OFFLINE:
  163.             log.error('finish_update exiting early, state is %r, reason is %r', self.state, self.offline_reason)
  164.             return None
  165.         
  166.         if update is None:
  167.             log.warning('two updates were running at the same time')
  168.             return None
  169.         
  170.         
  171.         try:
  172.             (updated_emails, updated_count) = update
  173.             self.updated_emails = True
  174.             self._received_emails(updated_emails, updated_count)
  175.         except (TypeError, ValueError):
  176.             e = None
  177.             log.error('Invalid response from real_update: %r', update)
  178.  
  179.  
  180.     
  181.     def real_update(self):
  182.         if self.update_lock.acquire(False):
  183.             
  184.             try:
  185.                 result = self.get_yMsgs()
  186.                 if result:
  187.                     return self._process_update_result(result)
  188.                 else:
  189.                     log.info('Got bad result from get_yMsgs: %r', result)
  190.                     raise Exception('bad result')
  191.             finally:
  192.                 self.update_lock.release()
  193.  
  194.         
  195.  
  196.     real_update = threaded(real_update)
  197.     
  198.     def _process_update_result(self, result):
  199.         (msgs, incount) = result
  200.         updated_count = incount
  201.         emails = []
  202.         for msg in msgs:
  203.             if msg.get('flags', { }).get('isRead', False):
  204.                 continue
  205.             
  206.             from_ = msg.get('from', { })
  207.             if not from_:
  208.                 fromname = ''
  209.             else:
  210.                 fromname = from_.get('name', from_.get('email', ''))
  211.             e = Email(id = msg['mid'], fromname = fromname, sendtime = datetime.fromtimestamp(msg['receivedDate']), subject = msg.get('subject', u''), attachments = [
  212.                 True] * msg.get('flags', { }).get('hasAttachment', 0))
  213.             emails.append(e)
  214.         
  215.         updated_emails = emails
  216.         log.info('reporting %d emails', incount)
  217.         return (updated_emails, updated_count)
  218.  
  219.     
  220.     def get_auth_form(self):
  221.         import ClientForm as ClientForm
  222.         
  223.         try:
  224.             forms = ClientForm.ParseResponse(self.http_opener.open('https://mail.yahoo.com'), backwards_compat = False)
  225.             for f in forms:
  226.                 if f.action == 'https://login.yahoo.com/config/login':
  227.                     form = f
  228.                     break
  229.                     continue
  230.             else:
  231.                 raise AssertionError('there should be a login form here')
  232.         except Exception:
  233.             e = None
  234.             traceback.print_exc()
  235.             form = ClientForm.HTMLForm('https://login.yahoo.com/config/login?', method = 'POST')
  236.             form.new_control('hidden', '.done', {
  237.                 'value': 'http://mail.yahoo.com' })
  238.             form.new_control('text', 'login', {
  239.                 'value': self.name.encode('utf-8') })
  240.             form.new_control('text', 'passwd', {
  241.                 'value': self._decryptedpw().encode('utf-8') })
  242.             form.new_control('hidden', '.save', {
  243.                 'value': 'Sign+In' })
  244.             form.new_control('hidden', '.done', {
  245.                 'value': 'http://mail.yahoo.com' })
  246.  
  247.         form['login'] = self.name.encode('utf-8')
  248.         form['passwd'] = self._decryptedpw().encode('utf-8')
  249.         return form
  250.  
  251.     
  252.     def authenticate(self):
  253.         log.info('authenticating')
  254.         form = self.get_auth_form()
  255.         
  256.         try:
  257.             resp = self.http_opener.open(form.click())
  258.         except Exception:
  259.             e = None
  260.             raise YahooMailException('failed to load url: %r' % e)
  261.  
  262.         respdata = resp.read()
  263.         resp.close()
  264.         respurl = resp.geturl()
  265.         if '/login' in respurl:
  266.             self.jar._cookies_lock.__enter__()
  267.             
  268.             try:
  269.                 self.jar._cookies['.yahoo.com']['/']['Y']
  270.                 self.jar._cookies['.yahoo.com']['/']['T']
  271.             except KeyError:
  272.                 self.jar._cookies_lock
  273.                 self.jar._cookies_lock
  274.                 log.warning('html was: %r', respdata)
  275.                 raise YahooMailAuthException('failed to authenticate')
  276.             except:
  277.                 self.jar._cookies_lock
  278.             finally:
  279.                 pass
  280.  
  281.         elif 'replica_agree?' in respurl:
  282.             pass
  283.         elif 'verify?' in respurl:
  284.             pass
  285.         else:
  286.             raise YahooMailAuthException('failed to authenticate, response url not expected', respurl)
  287.         
  288.         try:
  289.             resp = self.http_opener.open('http://mail.yahoo.com/')
  290.         except Exception:
  291.             e = None
  292.             raise YahooMailException('failed to load url: %r' % e)
  293.  
  294.         self.u = urlparse(resp.geturl())
  295.         resp.read()
  296.         resp.close()
  297.         
  298.         try:
  299.             self.user_data = self.api('GetUserData')
  300.             self._default_send_address = self.user_data['result']['data']['userSendPref']['defaultFromAddress']
  301.             
  302.             try:
  303.                 self.isBeta = int(self.user_data['result']['data']['userFeaturePref'].get('optInState', '2')) == 2
  304.             except ValueError:
  305.                 pass
  306.  
  307.         except Exception:
  308.             traceback.print_exc()
  309.  
  310.         log.info('Authenticated successfully')
  311.  
  312.     
  313.     def hostname(self):
  314.         if not hasattr(self, 'u'):
  315.             self.authenticate()
  316.         
  317.         return self.u.hostname
  318.  
  319.     hostname = property(hostname)
  320.     
  321.     def get_yMsgs(self):
  322.         log.info('get_yMsgs')
  323.         
  324.         try:
  325.             nummessages = _[1][0]['unread']
  326.         except YahooMailAuthException:
  327.             raise 
  328.         except Exception:
  329.             nummessages = 25
  330.  
  331.         nummessages = min(nummessages, 25)
  332.         result = self.api('ListMessages', fid = 'Inbox', numMid = 0, groupBy = 'unRead', startMid = 0, numInfo = nummessages, sortKey = 'date', sortOrder = 'down')
  333.         incount = result['result']['folder']['unread']
  334.         incount = int(incount)
  335.         return (result['result']['messageInfo'], incount)
  336.  
  337.     
  338.     def sort_emails(self, new = None):
  339.         pass
  340.  
  341.     
  342.     def open_url(self, url, data = None):
  343.         log.debug('open_url called from %s', get_func_name(2))
  344.         return self._open_url(url, data)
  345.  
  346.     
  347.     def _open_url(self, url, data = None):
  348.         datastring = None if not data else ' with data: ' + data
  349.         log.info('opening url: ' + url + datastring)
  350.         
  351.         try:
  352.             response = self.http_opener.open(url, data)
  353.         except Exception:
  354.             e = None
  355.             ex = YahooMailException('failed to load url: %r' % e)
  356.             log.error('%r', ex)
  357.             raise ex
  358.         else:
  359.             log.info('httpopen succeeded')
  360.             respurl = urlparse(response.geturl())
  361.             if 'login.yahoo.com' in respurl.hostname:
  362.                 log.info('login.yahoo.com in URL -- calling authenticate')
  363.                 self.authenticate()
  364.                 return self.open_url(url, data)
  365.             
  366.             log.info('reading data from httpresponse')
  367.             strdata = response.read()
  368.             return (strdata, respurl)
  369.         finally:
  370.             if 'response' in locals():
  371.                 log.debug('closing response')
  372.                 response.close()
  373.             
  374.  
  375.  
  376.     
  377.     def delete(self, msg):
  378.         EmailAccount.delete(self, msg)
  379.         self.api('DeleteMessages', fid = 'Inbox', mid = [
  380.             msg.id])
  381.  
  382.     delete = ymail_action(delete)
  383.     
  384.     def markAsRead(self, msg):
  385.         EmailAccount.markAsRead(self, msg)
  386.         self.api('FlagMessages', fid = 'Inbox', mid = [
  387.             msg.id], setFlags = {
  388.             'read': 1 })
  389.  
  390.     markAsRead = ymail_action(markAsRead)
  391.     
  392.     def reportSpam(self, msg):
  393.         EmailAccount.reportSpam(self, msg)
  394.         mark = dict(FlagMessages = dict(fid = 'Inbox', mid = [
  395.             msg.id], setFlags = {
  396.             'spam': 1,
  397.             'read': 1 }))
  398.         move = dict(MoveMessages = dict(sourceFid = 'Inbox', destinationFid = '%40B%40Bulk', mid = [
  399.             msg.id]))
  400.         self.api('BatchExecute', call = [
  401.             mark,
  402.             move])
  403.  
  404.     reportSpam = ymail_action(reportSpam)
  405.     
  406.     def open(self, msg):
  407.         EmailAccount.open(self, msg)
  408.         mid = msg.id
  409.         if self.isBeta:
  410.             mid = quote(mid)
  411.         
  412.         return UrlQuery('http://mrd.mail.yahoo.com/msg?', mid = mid, fid = 'Inbox')
  413.  
  414.     
  415.     def urlForEmail(self, msg):
  416.         
  417.         try:
  418.             if self.web_login:
  419.                 return str(self.make_login_string() + '&.done=' + quote(self.open(msg), safe = ''))
  420.             else:
  421.                 return self.open(msg)
  422.         except Exception:
  423.             e = None
  424.             self.warning(e)
  425.             return self.open(msg)
  426.  
  427.  
  428.     
  429.     def compose_link(self, to = '', subject = '', body = '', cc = '', bcc = ''):
  430.         extra = dict()
  431.         Body = body
  432.         subj = Subj = subject
  433.         To = to
  434.         Cc = cc
  435.         Bcc = bcc
  436.         for name in 'to To subj Subj subject body Body cc Cc bcc Bcc'.split():
  437.             if vars()[name]:
  438.                 val = vars()[name]
  439.                 if isinstance(val, unicode):
  440.                     val = val.encode('utf-8')
  441.                 
  442.                 extra[name.title()] = val
  443.                 continue
  444.         
  445.         return UrlQuery('http://compose.mail.yahoo.com/', **extra)
  446.  
  447.     
  448.     def compose(self, to = '', subject = '', body = '', cc = '', bcc = ''):
  449.         link = self.compose_link(to = to, subject = subject, body = body, cc = cc, bcc = bcc)
  450.         
  451.         try:
  452.             if self.web_login:
  453.                 return str(self.make_login_string() + '&.done=' + quote(link, safe = ''))
  454.             else:
  455.                 return link
  456.         except Exception:
  457.             e = None
  458.             self.warning(e)
  459.             return link
  460.  
  461.  
  462.     
  463.     def send_email(self, to = '', subject = '', body = '', cc = '', bcc = ''):
  464.         result = self.api('SendMessage', message = {
  465.             'subject': subject,
  466.             'from': {
  467.                 'email': self.email_address },
  468.             'to': {
  469.                 'email': to },
  470.             'simplebody': {
  471.                 'text': body } })
  472.         if result['error'] is not None:
  473.             log.error('send_email(to=%r, subject=%r, body=%r) = %r', to, subject, body, result['error'])
  474.             raise YahooMailException(result['error']['message'])
  475.         
  476.         return True
  477.  
  478.     send_email = threaded(send_email)
  479.     
  480.     def make_login_string(self):
  481.         self.jar._cookies_lock.__enter__()
  482.         
  483.         try:
  484.             y = yBrowserCookie(self.jar._cookies['.yahoo.com']['/']['Y'])
  485.             t = yBrowserCookie(self.jar._cookies['.yahoo.com']['/']['T'])
  486.         finally:
  487.             pass
  488.  
  489.         return 'http://msg.edit.yahoo.com/config/reset_cookies?&' + y + '&' + t + '&.ver=2'
  490.  
  491.     
  492.     def inbox_url(self):
  493.         
  494.         try:
  495.             if self.web_login and hasattr(self, 'u'):
  496.                 link = UrlQuery('http://mrd.mail.yahoo.com/inbox')
  497.                 loginstr = self.make_login_string()
  498.                 log.debug('returning login URL for yahoo inbox')
  499.                 return str(loginstr + '&.done=' + quote(link, safe = ''))
  500.             else:
  501.                 return 'http://mrd.mail.yahoo.com/inbox'
  502.         except Exception:
  503.             e = None
  504.             self.warning(e)
  505.             return 'http://mrd.mail.yahoo.com/inbox'
  506.  
  507.  
  508.     inbox_url = property(inbox_url)
  509.     
  510.     def api(self, method, **params):
  511.         foo = None
  512.         loads = loads
  513.         dumps = dumps
  514.         import simplejson
  515.         recursed = params.pop('_recursed', 0)
  516.         recurse = False
  517.         
  518.         try:
  519.             foo = self.http_opener.open(self.json_endpoint, dumps(dict(method = method, params = [
  520.                 params]))).read()
  521.             log.debug_s('got data from yahoo: %r', foo)
  522.             if not foo.startswith('{'):
  523.                 foo = foo.decode('z')
  524.             
  525.             foo = loads(foo)
  526.         except YahooMailAuthException:
  527.             raise 
  528.         except Exception:
  529.             e = None
  530.             if hasattr(e, 'read'):
  531.                 foo = e.read()
  532.                 log.debug('got error data from yahoo: %r', foo)
  533.             None if getattr(e, 'code', None) == 404 else None<EXCEPTION MATCH>YahooMailException
  534.             raise 
  535.         finally:
  536.             if recurse and recursed < 5:
  537.                 params['_recursed'] = recursed + 1
  538.                 return self.api(method, **params)
  539.             
  540.  
  541.         return foo
  542.  
  543.  
  544.  
  545. class FakeYmail(YahooMail):
  546.     count = 1337
  547.     
  548.     def __init__(self, username, password):
  549.         self.name = username
  550.         self.password = password
  551.         self.init_jar()
  552.  
  553.     
  554.     def _decryptedpw(self):
  555.         return self.password
  556.  
  557.     
  558.     def __len__(self):
  559.         return 1337
  560.  
  561.  
  562. if __name__ == '__main__':
  563.     import main
  564.     main.setup_log_system()
  565.     f = FakeYmail('username', 'passwordShouldNotBeInSourceCode')
  566.     f.authenticate()
  567.     from pprint import pprint
  568.     msgs = [ m for m in f.get_yMsgs()[0] ]
  569.     print len(msgs)
  570.     pprint(msgs)
  571.  
  572.  
  573. class yBrowserCookie(str):
  574.     
  575.     def __new__(cls, cookie):
  576.         return str.__new__(cls, '.' + cookie.name.lower() + '=' + cookie.name + '=' + quote(cookie.value, safe = '/=') + ';+path=' + cookie.path + ';+domain=' + cookie.domain)
  577.  
  578.  
  579.